
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
import ZRText from 'zrender/lib/graphic/Text.js';
import { isFunction, retrieve2, extend, keys, trim } from 'zrender/lib/core/util.js';
import { SPECIAL_STATES, DISPLAY_STATES } from '../util/states.js';
import { deprecateReplaceLog } from '../util/log.js';
import { makeInner, interpolateRawValues } from '../util/model.js';
import { initProps, updateProps } from '../util/graphic.js';
var EMPTY_OBJ = {};
export function setLabelText(label, labelTexts) {
	for (var i = 0; i < SPECIAL_STATES.length; i++) {
		var stateName = SPECIAL_STATES[i];
		var text = labelTexts[stateName];
		var state = label.ensureState(stateName);
		state.style = state.style || {};
		state.style.text = text;
	}

	var oldStates = label.currentStates.slice();
	label.clearStates(true);
	label.setStyle({
		text: labelTexts.normal
	});
	label.useStates(oldStates, true);
}

function getLabelText(opt, stateModels, interpolatedValue) {
	var labelFetcher = opt.labelFetcher;
	var labelDataIndex = opt.labelDataIndex;
	var labelDimIndex = opt.labelDimIndex;
	var normalModel = stateModels.normal;
	var baseText;

	if (labelFetcher) {
		baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex, normalModel && normalModel.get('formatter'), interpolatedValue != null ? {
			interpolatedValue: interpolatedValue
		} : null);
	}

	if (baseText == null) {
		baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt, interpolatedValue) : opt.defaultText;
	}

	var statesText = {
		normal: baseText
	};

	for (var i = 0; i < SPECIAL_STATES.length; i++) {
		var stateName = SPECIAL_STATES[i];
		var stateModel = stateModels[stateName];
		statesText[stateName] = retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, stateName, null, labelDimIndex, stateModel && stateModel.get('formatter')) : null, baseText);
	}

	return statesText;
}

function setLabelStyle(targetEl, labelStatesModels, opt, stateSpecified // TODO specified position?
) {
	opt = opt || EMPTY_OBJ;
	var isSetOnText = targetEl instanceof ZRText;
	var needsCreateText = false;

	for (var i = 0; i < DISPLAY_STATES.length; i++) {
		var stateModel = labelStatesModels[DISPLAY_STATES[i]];

		if (stateModel && stateModel.getShallow('show')) {
			needsCreateText = true;
			break;
		}
	}

	var textContent = isSetOnText ? targetEl : targetEl.getTextContent();

	if (needsCreateText) {
		if (!isSetOnText) {
			// Reuse the previous
			if (!textContent) {
				textContent = new ZRText();
				targetEl.setTextContent(textContent);
			} // Use same state proxy

			if (targetEl.stateProxy) {
				textContent.stateProxy = targetEl.stateProxy;
			}
		}

		var labelStatesTexts = getLabelText(opt, labelStatesModels);
		var normalModel = labelStatesModels.normal;
		var showNormal = !!normalModel.getShallow('show');
		var normalStyle = createTextStyle(normalModel, stateSpecified && stateSpecified.normal, opt, false, !isSetOnText);
		normalStyle.text = labelStatesTexts.normal;

		if (!isSetOnText) {
			// Always create new
			targetEl.setTextConfig(createTextConfig(normalModel, opt, false));
		}

		for (var i = 0; i < SPECIAL_STATES.length; i++) {
			var stateName = SPECIAL_STATES[i];
			var stateModel = labelStatesModels[stateName];

			if (stateModel) {
				var stateObj = textContent.ensureState(stateName);
				var stateShow = !!retrieve2(stateModel.getShallow('show'), showNormal);

				if (stateShow !== showNormal) {
					stateObj.ignore = !stateShow;
				}

				stateObj.style = createTextStyle(stateModel, stateSpecified && stateSpecified[stateName], opt, true, !isSetOnText);
				stateObj.style.text = labelStatesTexts[stateName];

				if (!isSetOnText) {
					var targetElEmphasisState = targetEl.ensureState(stateName);
					targetElEmphasisState.textConfig = createTextConfig(stateModel, opt, true);
				}
			}
		} // PENDING: if there is many requirements that emphasis position
		// need to be different from normal position, we might consider
		// auto silent is those cases.

		textContent.silent = !!normalModel.getShallow('silent'); // Keep x and y

		if (textContent.style.x != null) {
			normalStyle.x = textContent.style.x;
		}

		if (textContent.style.y != null) {
			normalStyle.y = textContent.style.y;
		}

		textContent.ignore = !showNormal; // Always create new style.

		textContent.useStyle(normalStyle);
		textContent.dirty();

		if (opt.enableTextSetter) {
			labelInner(textContent).setLabelText = function (interpolatedValue) {
				var labelStatesTexts = getLabelText(opt, labelStatesModels, interpolatedValue);
				setLabelText(textContent, labelStatesTexts);
			};
		}
	} else if (textContent) {
		// Not display rich text.
		textContent.ignore = true;
	}

	targetEl.dirty();
}

export { setLabelStyle };
export function getLabelStatesModels(itemModel, labelName) {
	labelName = labelName || 'label';
	var statesModels = {
		normal: itemModel.getModel(labelName)
	};

	for (var i = 0; i < SPECIAL_STATES.length; i++) {
		var stateName = SPECIAL_STATES[i];
		statesModels[stateName] = itemModel.getModel([stateName, labelName]);
	}

	return statesModels;
}
/**
 * Set basic textStyle properties.
 */

export function createTextStyle(textStyleModel, specifiedTextStyle, // Fixed style in the code. Can't be set by model.
	opt, isNotNormal, isAttached // If text is attached on an element. If so, auto color will handling in zrender.
) {
	var textStyle = {};
	setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached);
	specifiedTextStyle && extend(textStyle, specifiedTextStyle); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);

	return textStyle;
}
export function createTextConfig(textStyleModel, opt, isNotNormal) {
	opt = opt || {};
	var textConfig = {};
	var labelPosition;
	var labelRotate = textStyleModel.getShallow('rotate');
	var labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5);
	var labelOffset = textStyleModel.getShallow('offset');
	labelPosition = textStyleModel.getShallow('position') || (isNotNormal ? null : 'inside'); // 'outside' is not a valid zr textPostion value, but used
	// in bar series, and magric type should be considered.

	labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top');

	if (labelPosition != null) {
		textConfig.position = labelPosition;
	}

	if (labelOffset != null) {
		textConfig.offset = labelOffset;
	}

	if (labelRotate != null) {
		labelRotate *= Math.PI / 180;
		textConfig.rotation = labelRotate;
	}

	if (labelDistance != null) {
		textConfig.distance = labelDistance;
	} // fill and auto is determined by the color of path fill if it's not specified by developers.

	textConfig.outsideFill = textStyleModel.get('color') === 'inherit' ? opt.inheritColor || null : 'auto';
	return textConfig;
}
/**
 * The uniform entry of set text style, that is, retrieve style definitions
 * from `model` and set to `textStyle` object.
 *
 * Never in merge mode, but in overwrite mode, that is, all of the text style
 * properties will be set. (Consider the states of normal and emphasis and
 * default value can be adopted, merge would make the logic too complicated
 * to manage.)
 */

function setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached) {
	// Consider there will be abnormal when merge hover style to normal style if given default value.
	opt = opt || EMPTY_OBJ;
	var ecModel = textStyleModel.ecModel;
	var globalTextStyle = ecModel && ecModel.option.textStyle; // Consider case:
	// {
	//     data: [{
	//         value: 12,
	//         label: {
	//             rich: {
	//                 // no 'a' here but using parent 'a'.
	//             }
	//         }
	//     }],
	//     rich: {
	//         a: { ... }
	//     }
	// }

	var richItemNames = getRichItemNames(textStyleModel);
	var richResult;

	if (richItemNames) {
		richResult = {};

		for (var name_1 in richItemNames) {
			if (richItemNames.hasOwnProperty(name_1)) {
				// Cascade is supported in rich.
				var richTextStyle = textStyleModel.getModel(['rich', name_1]); // In rich, never `disableBox`.
				// FIXME: consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`,
				// the default color `'blue'` will not be adopted if no color declared in `rich`.
				// That might confuses users. So probably we should put `textStyleModel` as the
				// root ancestor of the `richTextStyle`. But that would be a break change.

				setTokenTextStyle(richResult[name_1] = {}, richTextStyle, globalTextStyle, opt, isNotNormal, isAttached, false, true);
			}
		}
	}

	if (richResult) {
		textStyle.rich = richResult;
	}

	var overflow = textStyleModel.get('overflow');

	if (overflow) {
		textStyle.overflow = overflow;
	}

	var margin = textStyleModel.get('minMargin');

	if (margin != null) {
		textStyle.margin = margin;
	}

	setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, true, false);
} // Consider case:
// {
//     data: [{
//         value: 12,
//         label: {
//             rich: {
//                 // no 'a' here but using parent 'a'.
//             }
//         }
//     }],
//     rich: {
//         a: { ... }
//     }
// }
// TODO TextStyleModel

function getRichItemNames(textStyleModel) {
	// Use object to remove duplicated names.
	var richItemNameMap;

	while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {
		var rich = (textStyleModel.option || EMPTY_OBJ).rich;

		if (rich) {
			richItemNameMap = richItemNameMap || {};
			var richKeys = keys(rich);

			for (var i = 0; i < richKeys.length; i++) {
				var richKey = richKeys[i];
				richItemNameMap[richKey] = 1;
			}
		}

		textStyleModel = textStyleModel.parentModel;
	}

	return richItemNameMap;
}

var TEXT_PROPS_WITH_GLOBAL = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'];
var TEXT_PROPS_SELF = ['align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign', 'ellipsis'];
var TEXT_PROPS_BOX = ['padding', 'borderWidth', 'borderRadius', 'borderDashOffset', 'backgroundColor', 'borderColor', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'];

function setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, isBlock, inRich) {
	// In merge mode, default value should not be given.
	globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ;
	var inheritColor = opt && opt.inheritColor;
	var fillColor = textStyleModel.getShallow('color');
	var strokeColor = textStyleModel.getShallow('textBorderColor');
	var opacity = retrieve2(textStyleModel.getShallow('opacity'), globalTextStyle.opacity);

	if (fillColor === 'inherit' || fillColor === 'auto') {
		if (process.env.NODE_ENV !== 'production') {
			if (fillColor === 'auto') {
				deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
			}
		}

		if (inheritColor) {
			fillColor = inheritColor;
		} else {
			fillColor = null;
		}
	}

	if (strokeColor === 'inherit' || strokeColor === 'auto') {
		if (process.env.NODE_ENV !== 'production') {
			if (strokeColor === 'auto') {
				deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
			}
		}

		if (inheritColor) {
			strokeColor = inheritColor;
		} else {
			strokeColor = null;
		}
	}

	if (!isAttached) {
		// Only use default global textStyle.color if text is individual.
		// Otherwise it will use the strategy of attached text color because text may be on a path.
		fillColor = fillColor || globalTextStyle.color;
		strokeColor = strokeColor || globalTextStyle.textBorderColor;
	}

	if (fillColor != null) {
		textStyle.fill = fillColor;
	}

	if (strokeColor != null) {
		textStyle.stroke = strokeColor;
	}

	var textBorderWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth);

	if (textBorderWidth != null) {
		textStyle.lineWidth = textBorderWidth;
	}

	var textBorderType = retrieve2(textStyleModel.getShallow('textBorderType'), globalTextStyle.textBorderType);

	if (textBorderType != null) {
		textStyle.lineDash = textBorderType;
	}

	var textBorderDashOffset = retrieve2(textStyleModel.getShallow('textBorderDashOffset'), globalTextStyle.textBorderDashOffset);

	if (textBorderDashOffset != null) {
		textStyle.lineDashOffset = textBorderDashOffset;
	}

	if (!isNotNormal && opacity == null && !inRich) {
		opacity = opt && opt.defaultOpacity;
	}

	if (opacity != null) {
		textStyle.opacity = opacity;
	} // TODO

	if (!isNotNormal && !isAttached) {
		// Set default finally.
		if (textStyle.fill == null && opt.inheritColor) {
			textStyle.fill = opt.inheritColor;
		}
	} // Do not use `getFont` here, because merge should be supported, where
	// part of these properties may be changed in emphasis style, and the
	// others should remain their original value got from normal style.

	for (var i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) {
		var key = TEXT_PROPS_WITH_GLOBAL[i];
		var val = retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]);

		if (val != null) {
			textStyle[key] = val;
		}
	}

	for (var i = 0; i < TEXT_PROPS_SELF.length; i++) {
		var key = TEXT_PROPS_SELF[i];
		var val = textStyleModel.getShallow(key);

		if (val != null) {
			textStyle[key] = val;
		}
	}

	if (textStyle.verticalAlign == null) {
		var baseline = textStyleModel.getShallow('baseline');

		if (baseline != null) {
			textStyle.verticalAlign = baseline;
		}
	}

	if (!isBlock || !opt.disableBox) {
		for (var i = 0; i < TEXT_PROPS_BOX.length; i++) {
			var key = TEXT_PROPS_BOX[i];
			var val = textStyleModel.getShallow(key);

			if (val != null) {
				textStyle[key] = val;
			}
		}

		var borderType = textStyleModel.getShallow('borderType');

		if (borderType != null) {
			textStyle.borderDash = borderType;
		}

		if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) {
			if (process.env.NODE_ENV !== 'production') {
				if (textStyle.backgroundColor === 'auto') {
					deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\'');
				}
			}

			textStyle.backgroundColor = inheritColor;
		}

		if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) {
			if (process.env.NODE_ENV !== 'production') {
				if (textStyle.borderColor === 'auto') {
					deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\'');
				}
			}

			textStyle.borderColor = inheritColor;
		}
	}
}

export function getFont(opt, ecModel) {
	var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
	return trim([// FIXME in node-canvas fontWeight is before fontStyle
		opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '', opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '', (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px', opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'].join(' '));
}
export var labelInner = makeInner();
export function setLabelValueAnimation(label, labelStatesModels, value, getDefaultText) {
	if (!label) {
		return;
	}

	var obj = labelInner(label);
	obj.prevValue = obj.value;
	obj.value = value;
	var normalLabelModel = labelStatesModels.normal;
	obj.valueAnimation = normalLabelModel.get('valueAnimation');

	if (obj.valueAnimation) {
		obj.precision = normalLabelModel.get('precision');
		obj.defaultInterpolatedText = getDefaultText;
		obj.statesModels = labelStatesModels;
	}
}
export function animateLabelValue(textEl, dataIndex, data, animatableModel, labelFetcher) {
	var labelInnerStore = labelInner(textEl);

	if (!labelInnerStore.valueAnimation || labelInnerStore.prevValue === labelInnerStore.value) {
		// Value not changed, no new label animation
		return;
	}

	var defaultInterpolatedText = labelInnerStore.defaultInterpolatedText; // Consider the case that being animating, do not use the `obj.value`,
	// Otherwise it will jump to the `obj.value` when this new animation started.

	var currValue = retrieve2(labelInnerStore.interpolatedValue, labelInnerStore.prevValue);
	var targetValue = labelInnerStore.value;

	function during(percent) {
		var interpolated = interpolateRawValues(data, labelInnerStore.precision, currValue, targetValue, percent);
		labelInnerStore.interpolatedValue = percent === 1 ? null : interpolated;
		var labelText = getLabelText({
			labelDataIndex: dataIndex,
			labelFetcher: labelFetcher,
			defaultText: defaultInterpolatedText ? defaultInterpolatedText(interpolated) : interpolated + ''
		}, labelInnerStore.statesModels, interpolated);
		setLabelText(textEl, labelText);
	}

	textEl.percent = 0;
	(labelInnerStore.prevValue == null ? initProps : updateProps)(textEl, {
		// percent is used to prevent animation from being aborted #15916
		percent: 1
	}, animatableModel, dataIndex, null, during);
}